package com.apache.passport.tomcat;

import com.apache.tools.StrUtil;
import org.apache.catalina.connector.Connector;
import org.apache.catalina.valves.AccessLogValve;
import org.apache.catalina.valves.Constants;
import org.apache.coyote.AbstractProtocol;
import org.apache.coyote.ajp.AjpNioProtocol;
import org.apache.coyote.http11.Http11NioProtocol;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory;
import org.springframework.boot.context.embedded.tomcat.TomcatConnectorCustomizer;
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;

import java.io.File;
import java.nio.charset.Charset;

@Configuration
public class WebServerConfiguration {

    @Autowired
    private Environment env;

    @Bean
    public EmbeddedServletContainerFactory createEmbeddedServletContainerFactory() {
        TomcatEmbeddedServletContainerFactory tomcat = new TomcatEmbeddedServletContainerFactory();
        tomcat.setUriEncoding(Charset.forName("UTF-8"));
        tomcat.setPort(Integer.parseInt(doNull(env.getProperty("spring.tomcat.port"), "8080")));
        //设置Tomcat的根目录
        String baseDirectory = env.getProperty("spring.tomcat.baseDirectory");
        if (!isNull(baseDirectory)) {
            tomcat.setBaseDirectory(new File(baseDirectory));
            //设置访问日志存放目录
            tomcat.addContextValves(getLogAccessLogValue(baseDirectory));
        }
        tomcat.addConnectorCustomizers(new MyTomcatConnectorCustomizer());
        if (StrUtil.isNotNull(env.getProperty("spring.tomcat.ajp.port"))) {
            tomcat.addAdditionalTomcatConnectors(createAjpConnector());//createSslConnector(),
        }
        return tomcat;
    }

    /**
     * ajp配置
     */
    private Connector createAjpConnector() {
        Connector connector = new Connector("org.apache.coyote.ajp.AjpNioProtocol");
        AjpNioProtocol protocol = (AjpNioProtocol) connector.getProtocolHandler();
        connector.setScheme("http");
        connector.setPort(
                Integer.parseInt(doNull(env.getProperty("spring.tomcat.ajp.port"), "8009")));
        setHttpParams(protocol);
        return connector;
    }

    private Connector createSslConnector() {
        Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
        Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();
        try {
            connector.setScheme("https");
            protocol.setSSLEnabled(true);
            connector.setPort(
                    Integer.parseInt(doNull(env.getProperty("spring.tomcat.ssl.port"), "8443")));
            if (!isNull(env.getProperty("spring.tomcat.ssl.keyStore"))) {
                connector.setSecure(true);
                File truststore = new File(env.getProperty("spring.tomcat.ssl.keyStore"));
                protocol.setKeystoreFile(truststore.getAbsolutePath());
                protocol.setKeystorePass(env.getProperty("spring.tomcat.ssl.keyPassword"));
                protocol.setKeyAlias(env.getProperty("spring.tomcat.ssl.keyAlias"));
            }
            setHttpParams(protocol);
            return connector;
        } catch (Exception ex) {
            throw new IllegalStateException("cant access keystore: [" + "keystore" + "]  ", ex);
        }
    }

    /**
     * 设置优化参数
     */
    private void setHttpParams(AbstractProtocol protocol) {
        //在任何给定的时间内，服务器将接受和处理的最大连接数
        protocol.setMaxConnections(
                Integer.parseInt(doNull(env.getProperty("spring.tomcat.maxConnections"), "10000")));
        //设置最大线程数，如果未配置默认值为200
        protocol.setMaxThreads(
                Integer.parseInt(doNull(env.getProperty("spring.tomcat.maxThreads"), "200")));
        //当请求已经被接受，但未被处理，也就是等待中的超时时间。单位为毫秒，默认值为60000
        protocol.setConnectionTimeout(
                Integer.parseInt(doNull(env.getProperty("spring.tomcat.timeOut"), "60000")));
        //当所有可能的请求处理线程都在使用时传入连接请求的最大队列长度，默认值为100
        //        protocol.setAcceptCount(
        //                Integer.parseInt(doNull(env.getProperty("spring.tomcat.acceptCount"), "500")));
        //minSpareThreads：线程的最小运行数目，这些始终保持运行。如果未指定，默认值为10
        protocol.setMinSpareThreads(
                Integer.parseInt(doNull(env.getProperty("spring.tomcat.minSpareThreads"), "10")));
        //maxHttpHeaderSize：请求和响应的HTTP头的最大大小，以字节为单位指定。如果没有指定，这个属性被设置为8192（8 KB）
        if (!isNull(env.getProperty("spring.tomcat.maxHttpHeaderSize"))) {
            protocol.setMinSpareThreads(
                    Integer.parseInt(env.getProperty("spring.tomcat.maxHttpHeaderSize")));
        }
    }

    /**
     * 设置访问日志存放目录
     */
    private AccessLogValve getLogAccessLogValue(String baseDirectory) {
        AccessLogValve accessLogValve = new AccessLogValve();
        accessLogValve.setDirectory(baseDirectory + "/logs");//存放地址
        accessLogValve.setEnabled(true);
        accessLogValve.setPattern(Constants.AccessLog.COMMON_PATTERN);
        accessLogValve.setEncoding("UTF-8");
        accessLogValve
                .setPrefix(StrUtil.doNull(env.getProperty("spring.tomcat.logFile"), "sso"));//文件名
        accessLogValve.setSuffix(".out");//文件后缀
        return accessLogValve;
    }

    private String doNull(String str, String defaultStr) {
        if (isNull(str)) {
            return defaultStr;
        }
        return str;
    }

    private boolean isNull(String str) {
        boolean mark = false;
        if (null == str || str.trim().equals("") || str.trim().equalsIgnoreCase("null")) {
            mark = true;
        }
        return mark;
    }

    class MyTomcatConnectorCustomizer implements TomcatConnectorCustomizer {

        public void customize(Connector connector) {
            Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();
            setHttpParams(protocol);
        }
    }
}
